package ca.ubc.eece310.project;

/**
 * EECE 310 Term Project Fall 2009
 * @author Matthew Fong, Herman Lee, Scott Pearson
 */

import java.io.*;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.Scanner;

import javax.swing.table.AbstractTableModel;


public class LogTableModel extends AbstractTableModel {

	/**
	 * OVERVIEW: Datatype containing all the information for the log tables
	 * Rep-Invariant: type=0 || type=1, numLines >=0
	 * AF(c): c.data[i][j] | 0 <= i < c.elements.size
	 * 		  			   | 0 <= j < numLines
	 */

	private static final long serialVersionUID = 3955763864584512372L;

	private String[] columnNames = { "Date", "Downloaded", "Uploaded" };
	private Object[][] data;
	private int numLines = 0;
	private int type;

	// CONSTRUCTOR
	public LogTableModel(int t) {
		/**
		 * REQUIRES: 0 <= t <= 2 EFFECTS: Constructs a LogTableModel, with t: 0
		 * per day t: 1 per month t: 2 per year and opens the log file, then
		 * fills data with the file data
		 */
		type = t;
		numLines = Log.getLogFileSize();
		updateTable();
	}

	@Override
	public int getColumnCount() {
		/**
		 * EFFECTS: Returns the number of columns
		 */
		return columnNames.length;
	}

	@Override
	public int getRowCount() {
		/**
		 * EFFECTS: Returns the length of the data array
		 */
		return data.length;
	}

	public String getColumnName(int col) {
		/**
		 * EFFECTS: Returns the column name;
		 */
		return columnNames[col];
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		/**
		 * REQUIRES: 0 < rowIndex < data.length, 0 < columnIndex <
		 * columnNames.length EFFECTS: Returns the Object in
		 * data[rowIndex][columnIndex]
		 */
		return data[rowIndex][columnIndex];
	}
	
	public Object[][] getData() {
		return data;
	}

	public void updateTable() {
		/**
		 * MODIFIES: data EFFECTS: Reads from the logfile and updates the table
		 * data
		 */
		DecimalFormat format = new DecimalFormat("#####.##");
		data = new Object[numLines][columnNames.length];
		int i = 0, j = 0;
		try {

			BufferedReader br = new BufferedReader(new FileReader(Log.getLogFile()));
			ArrayList<String> arl = new ArrayList<String>();
			
			String line = null;

			int currentMonth = 0;
			int pastMonth = -1;
			int currentYear = 0;
			int pastYear = -1;
			double totalDownThisPeriod = 0, totalUpThisPeriod = 0;
			while((line = br.readLine()) != null) {
				arl.add(line);
			}
			Collections.reverse(arl);
			Iterator<String> itr = arl.iterator();
			while (itr.hasNext()) {
				line = itr.next();
				Scanner scan = new Scanner(line).useDelimiter(",");
				if (type == 0) {
					data[i][0] = (String)scan.next();
					data[i][1] = format.format(scan.nextLong());
					data[i][2] = format.format(scan.nextLong());

					totalDownThisPeriod = Long.parseLong(data[i][1].toString());
					// 500KiB < totalDownThisMonth < 500MiB
					if (totalDownThisPeriod > (1024 * 512L) && totalDownThisPeriod < (1024 * 1024 * 512L))
						data[i][1] = format.format(totalDownThisPeriod / 1024 / 1024.0) + " MiB"; 
					// totalDownThisMonth > 500MiB
					else if (totalDownThisPeriod > (1024 * 1024 * 512L))
						data[i][1] = format.format(totalDownThisPeriod / 1024 / 1024 / 1024.0) + " GiB"; 
					else
						data[i][1] = format.format(totalDownThisPeriod / 1024.0) + " KiB"; 

					totalUpThisPeriod = Long.parseLong(data[i][2].toString());
					// 500KiB < totalDownThisMonth < 500MiB
					if (totalUpThisPeriod > 1024 * 512L && totalUpThisPeriod < 1024 * 1024 * 512L)
						data[i][2] = format.format(totalUpThisPeriod / 1024 / 1024.0) + " MiB"; 
					// totalDownThisMonth > 500MiB
					else if (totalUpThisPeriod > 1024 * 1024 * 512L)
						data[i][2] = format.format(totalUpThisPeriod / 1024 / 1024 / 1024.0) + " GiB"; 
					else
						data[i][2] = format.format(totalUpThisPeriod / 1024.0) + " KiB"; 
					
					i++;
				} else if (type == 1) {
					// KiB
					currentMonth = Integer.parseInt((String) line.subSequence(
							line.indexOf("/") + 1, line.indexOf("/", line
									.indexOf("/") + 1)));
					if (j == 0) {
						pastMonth = Integer.parseInt((String) line.subSequence(
								line.indexOf("/") + 1, line.indexOf("/", line
										.indexOf("/") + 1)));
						data[i][1] = 0.0;
						data[i][2] = 0.0;
					}

					if (currentMonth == pastMonth) {
						data[i][0] = (String) line.subSequence(line
								.indexOf("/") + 1, line.indexOf(","));
						scan.next();
						data[i][1] = (Double)data[i][1] + scan.nextDouble()/ 1024.0;
						data[i][2] = (Double)data[i][2] + scan.nextDouble()/ 1024.0;
						Calendar c = new GregorianCalendar();
						if(currentMonth == (c.get(Calendar.MONTH)+1)) {
							BandwidthLog.totalKBytesDownMonth = (long) Math.floor((Double)data[i][1]);
							BandwidthLog.totalKBytesUpMonth = (long) Math.floor((Double)data[i][2]);
						}

						pastMonth = currentMonth;
					} else {
						currentMonth = Integer.parseInt((String) line
								.subSequence(line.indexOf("/") + 1, line
										.indexOf("/", line.indexOf("/") + 1)));
						i++;
						data[i][1] = 0.0;
						data[i][2] = 0.0;
						data[i][0] = (String) line.subSequence(line.indexOf("/") + 1, line.indexOf(","));
						scan.next();
						data[i][1] = (Double)data[i][1] + scan.nextDouble()/ 1024.0;
						data[i][2] = (Double)data[i][2] + scan.nextDouble()/ 1024.0;
						pastMonth = currentMonth;
					}
				} else if (type == 2) {
					// MiB
					currentYear = Integer.parseInt((String) line.subSequence(
							line.indexOf("/", line.indexOf("/") + 1) + 1, line
									.indexOf(",")));
					if (j == 0) {
						pastYear = Integer.parseInt((String) line.subSequence(
								line.indexOf("/", line.indexOf("/") + 1) + 1,
								line.indexOf(",")));
						data[i][1] = 0.0;
						data[i][2] = 0.0;
					}
					if (currentYear == pastYear) {
						data[i][0] = (String) line.subSequence(line.indexOf(
								"/", line.indexOf("/") + 1) + 1, line
								.indexOf(","));
						
						scan.next();
						data[i][1] = (Double)data[i][1] + scan.nextDouble()/ 1024.0 /1024.0;
						data[i][2] = (Double)data[i][2] + scan.nextDouble()/ 1024.0 /1024.0;

						pastYear = currentYear;
						BandwidthLog.totalMBytesUpYear = (Double)data[i][2];
						BandwidthLog.totalMBytesDownYear = (Double)data[i][1];
						
					} else {
						currentYear = Integer.parseInt((String) line
								.subSequence(line.indexOf("/", line
										.indexOf("/") + 1) + 1, line
										.indexOf(",")));
						i++;
						data[i][1] = 0.0;
						data[i][2] = 0.0;
						data[i][0] = (String) line.subSequence(line.indexOf(
								"/", line.indexOf("/") + 1) + 1, line
								.indexOf(","));
						scan.next();
						data[i][1] = (Double)data[i][1] + scan.nextDouble()/ 1024.0 /1024.0;
						data[i][2] = (Double)data[i][2] + scan.nextDouble()/ 1024.0 /1024.0;
						pastYear = currentYear;
					}
				}
				j++;
				scan.close();
			}

			br.close();
			
			// format the logs
			if (type == 1) {
				// already in KiB
				for (int k = 0; k < data.length; k++) {
					if (data[k][0] != null) {
						totalDownThisPeriod = Double.parseDouble(data[k][1].toString());
						// 500KiB < totalDownThisMonth < 500MiB
						if (totalDownThisPeriod > 500 && totalDownThisPeriod < 1024 * 500)
							data[k][1] = format.format(totalDownThisPeriod / 1024.0) + " MiB";
						// totalDownThisMonth > 500MiB
						else if (totalDownThisPeriod > 1024 * 500)
							data[k][1] = format.format(totalDownThisPeriod / 1024 / 1024.0) + " GiB";
						else
							data[k][1] = format.format(totalDownThisPeriod) + " KiB";
						
						totalUpThisPeriod = Double.parseDouble(data[k][2].toString());
						// 500KiB < totalUpThisMonth < 500MiB
						if (totalUpThisPeriod > 500 && totalUpThisPeriod < 1024 * 500)
							data[k][2] = format.format(totalUpThisPeriod / 1024.0) + " MiB";
						// totalUpThisMonth > 500MiB
						else if (totalUpThisPeriod > 1024 * 500)
							data[k][2] = format.format(totalUpThisPeriod / 1024 / 1024.0) + " GiB";
						else 
							data[k][2] = format.format(totalUpThisPeriod) + " KiB";
					}
				}
			} else if (type == 2) {
				// already in MiB
				for (int k = 0; k < data.length; k++) {
					if (data[k][0] != null) {
						totalDownThisPeriod = Double.parseDouble(data[k][1].toString());
						// totalDownThisYear < 500MiB
						if (totalDownThisPeriod < 500) 
							data[k][1] = format.format(totalDownThisPeriod) + " MiB";
						// totalDownThisYear > 500MiB
						if (totalDownThisPeriod > 500) 
							data[k][1] = format.format(totalDownThisPeriod / 1024) + " GiB";
						
						totalUpThisPeriod = Double.parseDouble(data[k][2].toString());
						// totalUpThisYear < 500MiB
						if (totalUpThisPeriod < 500) 
							data[k][2] = format.format(totalUpThisPeriod) + " MiB";
						// totalUpThisYear > 500MiB
						if (totalUpThisPeriod > 500) 
							data[k][2] = format.format(totalUpThisPeriod / 1024) + " GiB";
						
					}
				}
			}

		} catch (IOException e) {
			System.out.println("couldn't find file");
		}
	}

	public boolean repOK() {
		/**
		 * EFFECTS: Returns true if the rep invariant holds for this
		 * 			else returns false
		 */
		if((type==0 || type==1) && numLines>=0)
			return true;
		return false;
	}
	
	public String toString() {
		/**
		 * EFFECTS: Returns a String representation
		 */
		String s = new String();
		s = columnNames[0] + "\t" + columnNames[1] + "\t" + columnNames[2] + "\n";
		for(int i=0; i<data.length; i++) {
			s = s + data[i][0] + "\t" + data[i][1] + "\t" + data[i][2] + "\n";
		}
		return s;
	}
}
